package com.crazy.common.file;

import static com.crazy.common.constants.HttpConstants.APPLICATION_OCTET_STREAM;
import static com.crazy.common.constants.HttpConstants.CONTENT_DISPOSITION;
import static com.crazy.common.constants.HttpConstants.CONT_DISP_ATTA;
import static com.crazy.common.constants.HttpConstants.ISO_8859_1;
import static com.crazy.common.Tools.getUUID;
import static org.apache.commons.io.FileUtils.deleteQuietly;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.multipart.MultipartFile;

/**
 * 文件上传工具类
 * 
 * @author Zhang Weiwei
 * @since 2013-8-31下午1:43:22
 */
public abstract class FileUploadUtil {
	/**
	 * 文件保存目录
	 */
	public static final String FILEDIR = "/upload";
	private static final String PATTERN = "yyyyMMdd";

	/**
	 * 处理上传文件核心方法
	 * 
	 * @author Zhang Weiwei
	 * @since 2013-8-31下午2:56:04
	 * @param request
	 *            servlet请求
	 * @param file
	 *            多媒体文件
	 * @param fileDirs
	 *            文件保存目录(支持多级目录,默认"/upload")
	 * @return
	 */
	public static FileUpload uploadFile(HttpServletRequest request,
			MultipartFile file, String... fileDirs) {
		HttpSession session = request.getSession();
		return uploadFile(session, file, fileDirs);
	}

	/**
	 * 处理上传文件核心方法
	 * 
	 * @author Zhang Weiwei
	 * @since 2013-10-4下午3:26:18
	 * @param session
	 *            http session
	 * @param file
	 *            多媒体文件
	 * @param fileDirs
	 *            文件保存目录(支持多级目录,默认"/upload")
	 * @return
	 */
	public static FileUpload uploadFile(HttpSession session,
			MultipartFile file, String... fileDirs) {
		ServletContext context = session.getServletContext();
		return uploadFile(context, file, fileDirs);
	}

	/**
	 * 处理上传文件核心方法
	 * 
	 * @author Zhang Weiwei
	 * @since 2013-9-21下午8:24:39
	 * @param context
	 *            servlet上下文
	 * @param file
	 *            多媒体文件
	 * @param fileDirs
	 *            文件保存目录(支持多级目录,默认"/upload")
	 * @return
	 */
	public static FileUpload uploadFile(ServletContext context,
			MultipartFile file, String... fileDirs) {
		String origFileName = file.getOriginalFilename();
		int index = getLastIndex(origFileName);
		String fileExt = origFileName.substring(index);
		String uuid = getUUID();
		String newFileName = uuid.concat(fileExt);
		String fileDir = null;
		if (fileDirs.length == 0) {
			fileDir = FILEDIR;
		} else {
			StringBuilder sb = new StringBuilder();
			for (String s : fileDirs) {
				sb.append(s);
			}
			fileDir = sb.toString();
		}
		DateFormat df = new SimpleDateFormat(PATTERN);
		String date = df.format(new Date());
		fileDir = fileDir.concat("/").concat(date);
		String relaFilePath = fileDir.concat("/").concat(newFileName);
		String realPath = context.getRealPath(fileDir);
		File dir = new File(realPath);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		String absoFilePath = realPath.concat("/").concat(newFileName);
		File destFile = new File(absoFilePath);
		try {
			file.transferTo(destFile);
		} catch (IllegalStateException | IOException e) {
			throw new RuntimeException(e);
		}
		absoFilePath = destFile.getPath();
		FileUpload fu = new FileUpload(origFileName, newFileName, relaFilePath,
				absoFilePath, file.getContentType());
		return fu;
	}

	private static int getLastIndex(String fileName) {
		int index = fileName.lastIndexOf(".");
		return index;
	}

	/**
	 * 下载文件核心处理方法
	 * 
	 * @author Zhang Weiwei
	 * @since 2013-10-4下午4:19:17
	 * @param context
	 *            servlet上下文
	 * @param response
	 *            servlet响应
	 * @param fileName
	 *            原始文件名
	 * @param filePath
	 *            文件保存相对路径
	 */
	public static void downloadFile(ServletContext context,
			HttpServletResponse response, String fileName, String filePath) {
		String realPath = context.getRealPath(filePath);
		downloadFile(response, fileName, realPath);
	}

	/**
	 * 下载文件核心处理方法
	 * 
	 * @author Zhang Weiwei
	 * @since 2013-10-4下午4:30:15
	 * @param response
	 *            servlet响应
	 * @param fileName
	 *            原始文件名
	 * @param filePath
	 *            文件保存绝对路径
	 */
	public static void downloadFile(HttpServletResponse response,
			String fileName, String filePath) {
		File file = new File(filePath);
		if (!file.exists()) {
			throw new RuntimeException("下载的文件不存在！");
		}
		try (InputStream input = new FileInputStream(file);
				OutputStream output = response.getOutputStream();) {
			String encoding = new String(fileName.getBytes(), ISO_8859_1);
			if (getLastIndex(fileName) == -1) {
				int index = getLastIndex(filePath);
				String fileExt = filePath.substring(index);
				encoding = encoding.concat(fileExt);
			}
			String value = CONT_DISP_ATTA.concat(encoding);
			response.addHeader(CONTENT_DISPOSITION, value);
			response.setContentType(APPLICATION_OCTET_STREAM);
			byte[] b = new byte[input.available()];
			input.read(b);
			output.write(b);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @param request
	 *            servlet请求
	 * @param filePath
	 *            文件保存相对路径
	 * @return 删除文件（支持目录、文件）
	 */
	public static boolean delete(HttpServletRequest request, String filePath) {
		ServletContext context = request.getServletContext();
		return delete(context, filePath);
	}

	/**
	 * 删除文件（支持目录、文件）
	 * 
	 * @author zhang weiwei
	 * @since 2013-11-4下午1:25:01
	 * @param context
	 *            servlet上下文
	 * @param filePath
	 *            文件保存相对路径
	 * @return
	 */
	public static boolean delete(ServletContext context, String filePath) {
		if (filePath == null) {
			return false;
		}
		String realPath = context.getRealPath(filePath);
		File file = new File(realPath);
		boolean result = deleteQuietly(file);
		return result;
	}

	/**
	 * 此内部类主要提供：原始文件名、新文件名、相对路径、绝对路径
	 * 
	 * @author Zhang Weiwei
	 * @since 2013-8-31下午2:55:19
	 */
	public static class FileUpload {
		private String origFileName;// 原始文件名
		private String newFileName;// 新文件名
		private String relaFilePath;// 相对路径
		private String absoFilePath;// 绝对路径
		private String contentType;// 文件类型

		/**
		 * @param origFileName
		 *            原始文件名
		 * @param newFileName
		 *            新文件名
		 * @param relaFilePath
		 *            相对路径
		 * @param absoFilePath
		 *            绝对路径
		 * @param contentType
		 *            文件类型
		 */
		private FileUpload(String origFileName, String newFileName,
				String relaFilePath, String absoFilePath, String contentType) {
			this.origFileName = origFileName;
			this.newFileName = newFileName;
			this.relaFilePath = relaFilePath;
			this.absoFilePath = absoFilePath;
			this.contentType = contentType;
		}

		/**
		 * 原始文件名
		 */
		public String getOrigFileName() {
			return origFileName;
		}

		/**
		 * 新文件名
		 */
		public String getNewFileName() {
			return newFileName;
		}

		/**
		 * 相对路径
		 */
		public String getRelaFilePath() {
			return relaFilePath;
		}

		/**
		 * 绝对路径
		 */
		public String getAbsoFilePath() {
			return absoFilePath;
		}

		/**
		 * 文件类型
		 */
		public String getContentType() {
			return contentType;
		}

		@Override
		public String toString() {
			return String
					.format("FileUpload [origFileName=%s, newFileName=%s, relaFilePath=%s, absoFilePath=%s, contentType=%s]",
							origFileName, newFileName, relaFilePath,
							absoFilePath, contentType);
		}
	}
}
